<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="GyPCv" id="GyPCv"><span data-lake-id="u4321cde4" id="u4321cde4">典型回答</span></h1>
  <p data-lake-id="ub822e102" id="ub822e102"><br></p>
  <p data-lake-id="uac4a9d95" id="uac4a9d95"><span data-lake-id="u20eb36cf" id="u20eb36cf">在MySQL中，最左前缀匹配是指在查询中利用索引的最左边的一部分来进行匹配。指你执行查询时，如果查询条件涉及到了组合索引的前几个列，MySQL 就可以利用这个复合索引来进行匹配。</span></p>
  <p data-lake-id="ue9ff516a" id="ue9ff516a"><span data-lake-id="u42601276" id="u42601276">​</span><br></p>
  <blockquote data-lake-id="ue53e47a4" id="ue53e47a4">
   <p data-lake-id="ufc9bed09" id="ufc9bed09"><span data-lake-id="u8112e77e" id="u8112e77e">组合索引，指的就是有多个字段组成的一个联合索引，如 idx_col1_col2_col3 (col1,col2,col3))</span></p>
  </blockquote>
  <p data-lake-id="u45930e49" id="u45930e49"><br></p>
  <p data-lake-id="u15699a0d" id="u15699a0d"><span data-lake-id="u47b7e2ac" id="u47b7e2ac">假如我们创建了一个组合索引 (col1, col2, col3)，如果你的查询条件是针对 col1 、 (col1, col2)或者(col1, col2, col3)，那么MySQL可以利用这个复合索引进行最左前缀匹配。</span></p>
  <p data-lake-id="u920aafd0" id="u920aafd0"><span data-lake-id="u56e6ede2" id="u56e6ede2">​</span><br></p>
  <p data-lake-id="u07e6948b" id="u07e6948b"><span data-lake-id="u91e18c2d" id="u91e18c2d">但是，如果查询条件涉及到的列只有 col2 或者 只有col3或者只有col2和col3，总之就是如果不包含col1的话，那么是没有遵守最左前缀匹配，那么通常情况下（不考虑索引跳跃扫描等其他优化），就不能利用这个索引进行最左前缀匹配。</span></p>
  <p data-lake-id="ubb1bdba8" id="ubb1bdba8"><span data-lake-id="u3dbc66d7" id="u3dbc66d7">​</span><br></p>
  <p data-lake-id="u01351b41" id="u01351b41"><span data-lake-id="uc271ff04" id="uc271ff04">并且，需要注意的是，最左前缀匹配和查询条件的顺序没有关系，不管你写的是</span><code data-lake-id="u29b0e4c0" id="u29b0e4c0"><span data-lake-id="ue847b466" id="ue847b466">where col1 = "Holiis" and col2 = "666" </span></code><span data-lake-id="u6c67ad15" id="u6c67ad15">还是 </span><code data-lake-id="u15261f29" id="u15261f29"><span data-lake-id="uaf9dc541" id="uaf9dc541">where col2 = "666" and col1 = "Holiis" </span></code><span data-lake-id="ud0ff425b" id="ud0ff425b"> 对结果都没有影响，该命中还是会命中。</span></p>
  <p data-lake-id="u59eeced7" id="u59eeced7"><span data-lake-id="u2044aa72" id="u2044aa72">​</span><br></p>
  <p data-lake-id="ube4a0e93" id="ube4a0e93"><span data-lake-id="ube4af303" id="ube4af303">但是，需要大家注意的是，很多人会以为创建一个组合索引 (col1, col2, col3)的时候，数据库会创建出三个索引 (col1)、 (col1, col2)和(col1, col2, col3)，这么理解其实是不对的，他创建的只是一棵B+树，只不过在这颗树中，他是先按照col1排序，在col1相同时再按照col2排序的，col2相同再按照col3排序。</span></p>
  <p data-lake-id="ud20ed0e0" id="ud20ed0e0"><span data-lake-id="u97fb9e09" id="u97fb9e09">​</span><br></p>
  <h1 data-lake-id="bahxI" id="bahxI"><span data-lake-id="ua4a5b4c1" id="ua4a5b4c1">扩展知识</span></h1>
  <h2 data-lake-id="Cpdsx" id="Cpdsx"><span data-lake-id="ua9e1fae7" id="ua9e1fae7">为什么要遵循最左前缀匹配</span></h2>
  <p data-lake-id="udcebcf26" id="udcebcf26" style="text-align: justify"><span data-lake-id="u4a3608a5" id="u4a3608a5">我们都知道，MySQL的Innodb引擎中，索引是通过B+树来实现的。不管是普通索引还是联合索引，都需要构造一个B+树的索引结构。</span></p>
  <p data-lake-id="u5b8677e0" id="u5b8677e0"><br></p>
  <p data-lake-id="uc2c45dd7" id="uc2c45dd7"><span data-lake-id="u20a002ff" id="u20a002ff">那么，我们都知道普通索引的存储结构是在B+树的每个非节点上记录索引的值，而这棵B+树的叶子节点上记录的是索引的值和聚簇索引（主键索引）的值的。</span></p>
  <p data-lake-id="u5f3b73c4" id="u5f3b73c4"><br></p>
  <p data-lake-id="u4a07ab0f" id="u4a07ab0f"><span data-lake-id="u4165e2bd" id="u4165e2bd">如：</span></p>
  <p data-lake-id="uf4141755" id="uf4141755"><br></p>
  <p data-lake-id="u95477d93" id="u95477d93"><img src="https://cdn.nlark.com/yuque/0/2023/jpeg/5378072/1692177314211-3d202703-795a-4281-8a55-2177e2866227.jpeg?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_32%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u1bf91085" id="u1bf91085"><br></p>
  <p data-lake-id="u8c9bd6c0" id="u8c9bd6c0"><span data-lake-id="uac3f7f6e" id="uac3f7f6e">那么，如果是联合索引的话，这棵B+树又是如何存储的呢？</span></p>
  <p data-lake-id="u2c3e46b9" id="u2c3e46b9"><br></p>
  <p data-lake-id="ub45826b7" id="ub45826b7"><span data-lake-id="u97c588b6" id="u97c588b6">在联合索引中，联合索引(age,name)也是一个B+树，非叶子节点中记录的是name,age两个字段的值，叶子节点中记录的是name，age两个字段以及主键id的值。</span></p>
  <p data-lake-id="u1b9c3eae" id="u1b9c3eae"><br></p>
  <p data-lake-id="u92119589" id="u92119589"><img src="https://cdn.nlark.com/yuque/0/2023/jpeg/5378072/1692177314203-4be40155-d2ea-4a7f-99e1-70e6c29d02e6.jpeg?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_31%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u891e7c2e" id="u891e7c2e"><br></p>
  <p data-lake-id="u8ab46e4c" id="u8ab46e4c"><span data-lake-id="u35d82b76" id="u35d82b76">在存储的过程中，如上图所示，当age不同时，按照age排序，当age相同时，则按照name排序。</span></p>
  <p data-lake-id="u25c996ba" id="u25c996ba"><br></p>
  <p data-lake-id="u597a1ca1" id="u597a1ca1"><span data-lake-id="u850e04ce" id="u850e04ce">所以，了解了索引的存储结构之后，我们就很容易理解最左前缀匹配了：</span><strong><span data-lake-id="u5cca17a4" id="u5cca17a4">因为索引底层是一个B+树，如果是联合索引的话，在构造B+树的时候，会先按照左边的key进行排序，左边的key相同时再依次按照右边的key排序。</span></strong></p>
  <p data-lake-id="uf957cb76" id="uf957cb76"><br></p>
  <p data-lake-id="u483e03be" id="u483e03be"><span data-lake-id="u25ef1f65" id="u25ef1f65">所以，</span><strong><span data-lake-id="ucdfb0cc6" id="ucdfb0cc6">在通过索引查询的时候，也需要遵守最左前缀匹配的原则，也就是需要从联合索引的最左边开始进行匹配，这时候就要求查询语句的where条件中，包含最左边的索引的值。</span></strong></p>
  <p data-lake-id="u7314b570" id="u7314b570"><br></p>
  <h2 data-lake-id="Mz3bk" id="Mz3bk"><span data-lake-id="ubae38a78" id="ubae38a78">​</span><br></h2>
 </body>
</html>